#include "stdcrc16.h"

void InvertUint8(uint8_t *dBuf,uint8_t *srcBuf)
{
  int i;
  uint8_t tmp[4];
  tmp[0] = 0;
  for(i=0;i< 8;i++) {
    if(srcBuf[0]& (1 << i))
      tmp[0]|=1<<(7-i);
  }
  dBuf[0] = tmp[0];
}

void InvertUint16(uint16_t *dBuf,uint16_t *srcBuf)
{
  int i;
  uint16_t tmp[4];
  tmp[0] = 0;
  for(i=0;i< 16;i++) {
    if(srcBuf[0]& (1 << i))
      tmp[0]|=1<<(15 - i);
  }
  dBuf[0] = tmp[0];
}

uint16_t CRC16_CCITT(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0x0000;
  uint16_t wCPoly = 0x1021;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    InvertUint8(&wChar,&wChar);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  InvertUint16(&wCRCin,&wCRCin);
  return (wCRCin);
}

uint16_t CRC16_CCITT_FALSE(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0xFFFF;
  uint16_t wCPoly = 0x1021;
  uint8_t wChar = 0;

  while (length--) {
    wChar = *(pdata++);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  return (wCRCin);
}

uint16_t CRC16_XMODEM(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0x0000;
  uint16_t wCPoly = 0x1021;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  return (wCRCin);
}

uint16_t CRC16_X25(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0xFFFF;
  uint16_t wCPoly = 0x1021;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    InvertUint8(&wChar,&wChar);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  InvertUint16(&wCRCin,&wCRCin);
  return (wCRCin^0xFFFF);
}

uint16_t CRC16_MODBUS(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0xFFFF;
  uint16_t wCPoly = 0x8005;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    InvertUint8(&wChar,&wChar);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  InvertUint16(&wCRCin,&wCRCin);
  return (wCRCin);
}

uint16_t CRC16_IBM(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0x0000;
  uint16_t wCPoly = 0x8005;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    InvertUint8(&wChar,&wChar);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  InvertUint16(&wCRCin,&wCRCin);
  return (wCRCin);
}

uint16_t CRC16_MAXIM(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0x0000;
  uint16_t wCPoly = 0x8005;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    InvertUint8(&wChar,&wChar);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
      if(wCRCin & 0x8000)
        wCRCin = (wCRCin << 1) ^ wCPoly;
      else
        wCRCin = wCRCin << 1;
    }
  }
  InvertUint16(&wCRCin,&wCRCin);
  return (wCRCin^0xFFFF);
}

uint16_t CRC16_USB(uint8_t *pdata, uint32_t length)
{
  uint16_t wCRCin = 0xFFFF;
  uint16_t wCPoly = 0x8005;
  uint8_t wChar = 0;
  while (length--) {
    wChar = *(pdata++);
    InvertUint8(&wChar,&wChar);
    wCRCin ^= (wChar << 8);
    for(int i = 0;i < 8;i++) {
    if(wCRCin & 0x8000)
      wCRCin = (wCRCin << 1) ^ wCPoly;
    else
      wCRCin = wCRCin << 1;
    }
  }
  InvertUint16(&wCRCin,&wCRCin);
  return (wCRCin^0xFFFF);
}
